home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 3
/
Cream of the Crop 3.iso
/
comm
/
wnos5src.zip
/
SOCKET.C
< prev
next >
Wrap
Text File
|
1993-08-09
|
45KB
|
1,960 lines
#include <stdio.h>
#ifdef __STDC__
#include <stdarg.h>
#endif
#include "global.h"
#include "config.h"
#include "mbuf.h"
#include "netuser.h"
#include "timer.h"
#include "iface.h"
#include "ip.h"
#include "tcp.h"
#ifdef UDP
#include "udp.h"
#endif
#include "ax25.h"
#include "netrom.h"
#include "nr4.h"
#include "proc.h"
#ifdef LZW
#include "lzw.h"
#endif
#include "usock.h"
#include "socket.h"
static void near autobind __ARGS((int s,int af));
static int near checkaddr __ARGS((int type,char *name,int namelen));
static void rip_recv __ARGS((struct raw_ip *rp));
void s_trcall __ARGS((struct tcb *tcb,int cnt));
void s_tscall __ARGS((struct tcb *tcb,int old,int new));
void s_ttcall __ARGS((struct tcb *tcb,int cnt));
#ifdef UDP
void s_urcall __ARGS((struct iface *iface,struct udp_cb *udp,int cnt));
#endif
static void trdiscard __ARGS((struct tcb *tcb,int cnt));
#ifdef NETROM
void s_nrcall __ARGS((struct nr4cb *cb,int cnt));
void s_nscall __ARGS((struct nr4cb *cb,int old,int new));
void s_ntcall __ARGS((struct nr4cb *cb,int cnt));
#endif
static int16 Lport = 1024;
char Badsocket[] = "Bad socket";
char Nosocket[] = "Can't create socket\n";
static struct usock *Usock = NULLUSOCK; /* Socket entry array */
int Nusock = DEFNSOCK; /* Number of socket entries */
/* The following two variables are needed because there can be only one
* socket listening on each of the AX.25 modes (I and UI)
*/
/* definition !! */
/*
int Axi_sock = -1; /* Socket number listening for AX25 connections */
/* defined in server.c */
#ifdef AX25
static int Axui_sock = -1; /* Socket number listening for AX25 UI frames */
#endif /* AX25 */
/* Initialize user socket array */
void
sockinit()
{
Usock = (struct usock *)mxalloc(Nusock * sizeof(struct usock));
}
/* Create a user socket, return socket index
* The mapping to actual protocols is as follows:
*
* ADDRESS FAMILY Stream Datagram Raw Seq. Packet
*
* AF_INET TCP UDP IP
* AF_AX25 I-frames UI-frames
* AF_NETROM NET/ROM L3 NET/ROM L4
* AF_LOCAL stream loopback packet loopback
*/
int
socket(
int af, /* Address family */
int type, /* Stream or datagram */
int protocol) /* Used for raw IP sockets */
{
struct usock *up;
int s;
errno = 0;
for(up = Usock; up < &Usock[Nusock]; up++)
if(up->type == NOTUSED)
break;
if(up == &Usock[Nusock]) {
/* None left */
errno = EMFILE;
return EOF;
}
s = (int)(up - Usock) + SOCKBASE;
up->refcnt = 1;
up->noblock = 0;
up->rdysock = -1;
up->cb.p = NULLCHAR;
up->name = up->peername = NULLCHAR;
up->namelen = up->peernamelen = 0;
up->owner = Curproc;
up->obuf = NULLBUF;
memset(up->errcodes,0,sizeof(up->errcodes));
memset(up->eol,0,sizeof(up->eol));
up->flush = '\n'; /* default is line buffered */
switch(af) {
case AF_LOCAL:
up->cb.local = (struct loc *)mxallocw(sizeof(struct loc));
up->cb.local->peer = up;
switch(type){
case SOCK_STREAM:
up->type = TYPE_LOCAL_STREAM;
up->cb.local->hiwat = LOCSFLOW;
break;
case SOCK_DGRAM:
up->type = TYPE_LOCAL_DGRAM;
up->cb.local->hiwat = LOCDFLOW;
break;
default:
xfree(up->cb.local);
errno = ESOCKTNOSUPPORT;
break;
}
break;
#ifdef AX25
case AF_AX25:
switch(type){
case SOCK_STREAM:
up->type = TYPE_AX25I;
break;
case SOCK_DGRAM:
up->type = TYPE_AX25UI;
break;
default:
errno = ESOCKTNOSUPPORT;
break;
}
strcpy(up->eol,AX_EOL);
break;
#endif
#ifdef NETROM
case AF_NETROM:
switch(type){
case SOCK_RAW:
up->type = TYPE_NETROML3;
up->cb.rnr = raw_nr((char)protocol);
break;
case SOCK_SEQPACKET:
up->type = TYPE_NETROML4;
break;
default:
errno = ESOCKTNOSUPPORT;
break;
}
strcpy(up->eol,AX_EOL);
break;
#endif
case AF_INET:
switch(type){
case SOCK_STREAM:
up->type = TYPE_TCP;
strcpy(up->eol,INET_EOL);
break;
case SOCK_DGRAM:
up->type = TYPE_UDP;
break;
case SOCK_RAW:
up->type = TYPE_RAW;
up->cb.rip = raw_ip(protocol,rip_recv);
up->cb.rip->user = s;
break;
default:
errno = ESOCKTNOSUPPORT;
break;
}
break;
default:
errno = EAFNOSUPPORT;
break;
}
if(errno)
return -1;
return s;
}
/* Attach a local address/port to a socket. If not issued before a connect
* or listen, will be issued automatically
*/
int
bind(
int s, /* Socket index */
char *name, /* Local name */
int namelen) /* Length of name */
{
struct usock *up;
union sp local;
struct socket lsock;
if((up = itop(s)) == NULLUSOCK){
return EOF;
}
if(up->type == TYPE_LOCAL_STREAM
|| up->type == TYPE_LOCAL_DGRAM
/* Bind has already been issued */
|| up->name != NULLCHAR) {
errno = EINVAL;
return EOF;
}
if(name == NULLCHAR){
errno = EFAULT;
return EOF;
}
if(checkaddr(up->type,name,namelen) == -1){
/* Incorrect length or family for chosen protocol */
errno = EAFNOSUPP;
return EOF;
}
/* Stash name in an allocated block */
up->name = mxallocw(namelen);
memcpy(up->name,name,namelen);
up->namelen = namelen;
/* Create control block for datagram sockets */
switch(up->type){
#ifdef UDP
case TYPE_UDP:
local.in = (struct sockaddr_in *)up->name;
lsock.address = local.in->sin_addr.s_addr;
lsock.port = local.in->sin_port;
up->cb.udp = open_udp(&lsock,s_urcall);
up->cb.udp->user = s;
break;
#endif
#ifdef AX25
case TYPE_AX25UI:
if(Axui_sock != -1){
errno = EADDRINUSE;
return EOF;
}
Axui_sock = s;
break;
#endif
}
return 0;
}
/* Post a listen on a socket */
int
listen(
int s, /* Socket index */
int backlog) /* 0 for a single connection, 1 for multiple connections */
{
struct usock *up;
union sp local;
struct socket lsock;
if((up = itop(s)) == NULLUSOCK){
return EOF;
}
if(up->type == TYPE_LOCAL_STREAM || up->type == TYPE_LOCAL_DGRAM){
errno = EINVAL;
return EOF;
}
if(up->cb.p != NULLCHAR){
errno = EISCONN;
return EOF;
}
switch(up->type){
case TYPE_TCP:
if(up->name == NULLCHAR)
autobind(s,AF_INET);
local.in = (struct sockaddr_in *)up->name;
lsock.address = local.in->sin_addr.s_addr;
lsock.port = local.in->sin_port;
up->cb.tcb = open_tcp(
&lsock,
NULLSOCK,
backlog ? TCP_SERVER : TCP_PASSIVE,
0,
s_trcall,
s_ttcall,
s_tscall,
0,
s);
break;
#ifdef AX25
case TYPE_AX25I:
if(up->name == NULLCHAR)
autobind(s,AF_AX25);
if(s != Axi_sock){
errno = EOPNOTSUPP;
return EOF;
}
local.ax = (struct sockaddr_ax *)up->name;
up->cb.ax25 = open_ax25(
NULLIF,
local.ax->ax25_addr,
NULLCHAR,
backlog ? AX_SERVER : AX_PASSIVE,
s_arcall,
s_atcall,
s_ascall,
s);
break;
#endif
#ifdef NETROM
case TYPE_NETROML4:
if(up->name == NULLCHAR)
autobind(s,AF_NETROM);
local.nr = (struct sockaddr_nr *)up->name;
up->cb.nr4 = open_nr4(
&local.nr->nr_addr,
NULLNRADDR,
backlog ? AX_SERVER : AX_PASSIVE,
s_nrcall,
s_ntcall,
s_nscall,
s);
break;
#endif
default:
/* Listen not supported on datagram sockets */
errno = EOPNOTSUPP;
return EOF;
}
return 0;
}
/* Initiate active open. For datagram sockets, merely bind the remote address. */
int
connect(
int s, /* Socket index */
char *peername, /* Peer name */
int peernamelen) /* Length of peer name */
{
struct usock *up;
union cb cb;
union sp local,remote;
struct socket lsock,fsock;
#ifdef AX25
struct iface *iface;
#endif
if((up = itop(s)) == NULLUSOCK){
return EOF;
}
if(up->type == TYPE_LOCAL_DGRAM || up->type == TYPE_LOCAL_STREAM){
errno = EINVAL;
return EOF;
}
if(peername == NULLCHAR){
/* Connect must specify a remote address */
errno = EFAULT;
return EOF;
}
if(checkaddr(up->type,peername,peernamelen) == -1){
errno = EAFNOSUPPORT;
return EOF;
}
/* Raw socket control blocks are created in socket() */
if(up->type != TYPE_RAW && up->type != TYPE_NETROML3 &&
up->cb.p != NULLCHAR){
errno = EISCONN;
return EOF;
}
up->peername = mxallocw(peernamelen);
memcpy(up->peername,peername,peernamelen);
up->peernamelen = peernamelen;
/* Set up the local socket structures */
if(up->name == NULLCHAR){
switch(up->type){
case TYPE_TCP:
#ifdef UDP
case TYPE_UDP:
#endif
case TYPE_RAW:
autobind(s,AF_INET);
break;
#ifdef AX25
case TYPE_AX25I:
case TYPE_AX25UI:
autobind(s,AF_AX25);
break;
#endif
#ifdef NETROM
case TYPE_NETROML3:
case TYPE_NETROML4:
autobind(s,AF_NETROM);
break;
#endif
}
}
switch(up->type){
case TYPE_TCP:
/* Construct the TCP-style ports from the sockaddr structs */
local.in = (struct sockaddr_in *)up->name;
remote.in = (struct sockaddr_in *)up->peername;
if(local.in->sin_addr.s_addr == INADDR_ANY)
/* Choose a local address */
local.in->sin_addr.s_addr = locaddr(remote.in->sin_addr.s_addr);
lsock.address = local.in->sin_addr.s_addr;
lsock.port = local.in->sin_port;
fsock.address = remote.in->sin_addr.s_addr;
fsock.port = remote.in->sin_port;
/* Open the TCB in active mode */
up->cb.tcb =
open_tcp(&lsock,&fsock,TCP_ACTIVE,0,s_trcall,s_ttcall,s_tscall,0,s);
/* Wait for the connection to complete */
while((cb.tcb = up->cb.tcb) != NULLTCB && cb.tcb->state != TCP_ESTABLISHED){
if(up->noblock){
errno = EWOULDBLOCK;
return EOF;
} else if((errno = (int)pwait(up)) != 0){
return EOF;
}
}
if(cb.tcb == NULLTCB){
/* Probably got refused */
xfree(up->peername);
up->peername = NULLCHAR;
errno = ECONNREFUSED;
return EOF;
}
break;
#ifdef UDP
case TYPE_UDP:
#endif
#ifdef AX25
case TYPE_AX25UI:
#endif
#ifdef NETROM
case TYPE_NETROML3:
#endif
case TYPE_RAW:
/* Control block already created by bind() */
break;
#ifdef AX25
case TYPE_AX25I:
local.ax = (struct sockaddr_ax *)up->name;
remote.ax = (struct sockaddr_ax *)up->peername;
if((iface = if_lookup(remote.ax->iface)) == NULLIF){
errno = EINVAL;
return EOF;
}
if(local.ax->ax25_addr[0] == '\0'){
/* The local address was unspecified; set it from
* the interface address
*/
memcpy(local.ax->ax25_addr,iface->hwaddr,AXALEN);
}
/* If we already have an AX25 link we can use it */
if((up->cb.ax25 = find_ax25(local.ax->ax25_addr,remote.ax->ax25_addr)) != NULLAX25
&& up->cb.ax25->state != DISCONNECTED
&& up->cb.ax25->user == -1) {
up->cb.ax25->user = s;
up->cb.ax25->r_upcall = s_arcall;
up->cb.ax25->t_upcall = s_atcall;
up->cb.ax25->s_upcall = s_ascall;
if(up->cb.ax25->state == CONNECTED)
return 0;
} else {
up->cb.ax25 = open_ax25(
iface,
local.ax->ax25_addr,
remote.ax->ax25_addr,
AX_ACTIVE,
s_arcall,
s_atcall,
s_ascall,
s);
}
/* Wait for the connection to complete */
while((cb.ax25 = up->cb.ax25) != NULLAX25 && cb.ax25->state != CONNECTED){
if(up->noblock){
errno = EWOULDBLOCK;
return EOF;
} else if((errno = (int)pwait(up)) != 0){
return EOF;
}
}
if(cb.ax25 == NULLAX25){
/* Connection probably already exists */
xfree(up->peername);
up->peername = NULLCHAR;
errno = ECONNREFUSED;
return EOF;
}
break;
#endif
#ifdef NETROM
case TYPE_NETROML4:
local.nr = (struct sockaddr_nr *)up->name;
remote.nr = (struct sockaddr_nr *)up->peername;
up->cb.nr4 = open_nr4(
&local.nr->nr_addr,
&remote.nr->nr_addr,
AX_ACTIVE,
s_nrcall,
s_ntcall,
s_nscall,
s);
/* Wait for the connection to complete */
while((cb.nr4 = up->cb.nr4) != NULLNR4CB && cb.nr4->state != NR4STCON){
if(up->noblock){
errno = EWOULDBLOCK;
return EOF;
} else if((errno = (int)pwait(up)) != 0){
return EOF;
}
}
if(cb.nr4 == NULLNR4CB){
/* Connection probably already exists */
xfree(up->peername);
up->peername = NULLCHAR;
errno = ECONNREFUSED;
return EOF;
}
break;
#endif
}
return 0;
}
/* Wait for a connection. Valid only for connection-oriented sockets. */
int
accept(
int s, /* Socket index */
char *peername, /* Peer name */
int *peernamelen) /* Length of peer name */
{
int i;
struct usock *up;
if((up = itop(s)) == NULLUSOCK){
return EOF;
}
if(up->type == TYPE_LOCAL_DGRAM || up->type == TYPE_LOCAL_STREAM){
errno = EINVAL;
return EOF;
}
if(up->cb.p == NULLCHAR){
errno = EOPNOTSUPP;
return EOF;
}
/* Accept is valid only for stream sockets */
switch(up->type){
case TYPE_TCP:
#ifdef AX25
case TYPE_AX25I:
#endif
#ifdef NETROM
case TYPE_NETROML4:
#endif
break;
default:
errno = EOPNOTSUPP;
return EOF;
}
/* Wait for the state-change upcall routine to signal us */
while(up->cb.p != NULLCHAR && up->rdysock == -1){
if(up->noblock){
errno = EWOULDBLOCK;
return EOF;
} else if((errno = (int)pwait(up)) != 0){
return EOF;
}
}
if(up->cb.p == NULLCHAR){
/* Blown away */
errno = EBADF;
return EOF;
}
i = up->rdysock;
up->rdysock = -1;
up = itop(i);
if(peername != NULLCHAR && peernamelen != 0){
*peernamelen = (int)min(up->peernamelen,*peernamelen);
memcpy(peername,up->peername,*peernamelen);
}
return i;
}
/* Low-level receive routine. Passes mbuf back to user; more efficient than
* higher-level functions recv() and recvfrom(). Datagram sockets ignore
* the len parameter.
*/
int
recv_mbuf(
int s, /* Socket index */
struct mbuf **bpp, /* Place to stash receive buffer */
int flags, /* Unused; will control out-of-band data, etc */
char *from, /* Peer address (only for datagrams) */
int *fromlen) /* Length of peer address */
{
struct usock *up;
int cnt = -1;
union cb cb;
struct socket fsocket;
#ifdef NETROM
struct nr3hdr n3hdr;
#endif
union sp remote;
struct ip ip;
struct mbuf *bp;
if((up = itop(s)) == NULLUSOCK){
return EOF;
}
if(up->ibuf != NULLBUF){
/* Return input buffer */
cnt = len_p(up->ibuf);
if(bpp != NULLBUFP)
*bpp = up->ibuf;
else
free_p(up->ibuf);
up->ibuf = NULLBUF;
return cnt;
}
switch(up->type){
case TYPE_LOCAL_STREAM:
case TYPE_LOCAL_DGRAM:
while(up->cb.local != NULLLOC && up->cb.local->q == NULLBUF
&& up->cb.local->peer != NULLUSOCK) {
if(up->noblock){
errno = EWOULDBLOCK;
return EOF;
} else if((errno = (int)pwait(up)) != 0){
return EOF;
}
}
if(up->cb.local == NULLLOC){
errno = EBADF;
return EOF;
}
if(up->cb.local->q == NULLBUF &&
up->cb.local->peer == NULLUSOCK){
errno = ENOTCONN;
return EOF;
}
/* For datagram sockets, this will return the
* first packet on the queue. For stream sockets,
* this will return everything.
*/
bp = dequeue(&up->cb.local->q);
if(up->cb.local->q == NULLBUF && (up->cb.local->flags & LOC_SHUTDOWN))
close_s(s);
psignal(up,0);
cnt = len_p(bp);
break;
case TYPE_TCP:
while((cb.tcb = up->cb.tcb) != NULLTCB
&& cb.tcb->r_upcall != trdiscard
&& (cnt = recv_tcp(cb.tcb,&bp,0)) == -1){
if(up->noblock){
errno = EWOULDBLOCK;
return EOF;
} else if((errno = (int)pwait(up)) != 0){
return EOF;
}
}
if(cb.tcb == NULLTCB){
/* Connection went away */
errno = ENOTCONN;
return EOF;
} else if(cb.tcb->r_upcall == trdiscard){
/* Receive shutdown has been done */
errno = ENOTCONN; /* CHANGE */
return EOF;
}
break;
#ifdef UDP
case TYPE_UDP:
while((cb.udp = up->cb.udp) != NULLUDP
&& (cnt = recv_udp(cb.udp,&fsocket,&bp)) == -1){
if(up->noblock){
errno = EWOULDBLOCK;
return EOF;
} else if((errno = (int)pwait(up)) != 0){
return EOF;
}
}
if(cb.udp == NULLUDP){
/* Connection went away */
errno = ENOTCONN;
return EOF;
}
if(from != NULLCHAR && fromlen != 0 && *fromlen >= SOCKSIZE){
remote.in = (struct sockaddr_in *)from;
remote.in->sin_family = AF_INET;
remote.in->sin_addr.s_addr = fsocket.address;
remote.in->sin_port = fsocket.port;
*fromlen = SOCKSIZE;
}
break;
#endif
case TYPE_RAW:
while((cb.rip = up->cb.rip) != NULLRIP
&& cb.rip->rcvq == NULLBUF){
if(up->noblock){
errno = EWOULDBLOCK;
return EOF;
} else if((errno = (int)pwait(up)) != 0){
return EOF;
}
}
if(cb.rip == NULLRIP){
/* Connection went away */
errno = ENOTCONN;
return EOF;
}
bp = dequeue(&cb.rip->rcvq);
ntohip(&ip,&bp);
cnt = len_p(bp);
if(from != NULLCHAR && fromlen != 0 && *fromlen >= SOCKSIZE){
remote.in = (struct sockaddr_in *)from;
remote.in->sin_family = AF_INET;
remote.in->sin_addr.s_addr = ip.source;
remote.in->sin_port = 0;
*fromlen = SOCKSIZE;
}
break;
#ifdef AX25
case TYPE_AX25I:
while((cb.ax25 = up->cb.ax25) != NULLAX25
&& (bp = recv_ax25(cb.ax25,0)) == NULLBUF){
if(up->noblock){
errno = EWOULDBLOCK;
return EOF;
} else if((errno = (int)pwait(up)) != 0){
return EOF;
}
}
if(cb.ax25 == NULLAX25){
/* Connection went away */
errno = ENOTCONN;
return EOF;
}
cnt = bp->cnt;
break;
case TYPE_AX25UI:
while(s == Axui_sock) {
if(up->noblock){
errno = EWOULDBLOCK;
return EOF;
}
}
if(s != Axui_sock){
errno = ENOTCONN;
return EOF;
}
bp = NULLBUF;
if(from != NULLCHAR && fromlen != NULLINT
&& *fromlen >= sizeof(struct sockaddr_ax)){
pullup(&bp,from,sizeof(struct sockaddr_ax));
*fromlen = sizeof(struct sockaddr_ax);
} else {
pullup(&bp,NULLCHAR,sizeof(struct sockaddr_ax));
}
cnt = len_p(bp);
break;
#endif
#ifdef NETROM
case TYPE_NETROML3:
while((cb.rnr = up->cb.rnr) != NULLRNR
&& cb.rnr->rcvq == NULLBUF){
if(up->noblock){
errno = EWOULDBLOCK;
return EOF;
} else if((errno = (int)pwait(up)) != 0){
return EOF;
}
}
if(cb.rnr == NULLRNR){
/* Connection went away */
errno = ENOTCONN;
return EOF;
}
bp = dequeue(&cb.rnr->rcvq);
ntohnr3(&n3hdr,&bp);
cnt = len_p(bp);
if(from != NULLCHAR && fromlen != NULLINT
&& *fromlen >= sizeof(struct sockaddr_nr)){
remote.nr = (struct sockaddr_nr *)from;
remote.nr->nr_family = AF_NETROM;
/* The callsign of the local user is not part of
NET/ROM level 3, so that field is not used here */
memcpy(remote.nr->nr_addr.node,n3hdr.source,AXALEN);
*fromlen = sizeof(struct sockaddr_nr);
}
break;
case TYPE_NETROML4:
while((cb.nr4 = up->cb.nr4) != NULLNR4CB
&& (bp = recv_nr4(cb.nr4,0)) == NULLBUF){
if(up->noblock){
errno = EWOULDBLOCK;
return EOF;
} else if((errno = (int)pwait(up)) != 0){
return EOF;
}
}
if(cb.nr4 == NULLNR4CB){
/* Connection went away */
errno = ENOTCONN;
return EOF;
}
cnt = bp->cnt;
break;
#endif
}
if(bpp != NULLBUFP)
*bpp = bp;
else
free_p(bp);
return cnt;
}
/* Low level send routine; user supplies mbuf for transmission. More
* efficient than send() or sendto(), the higher level interfaces.
* The "to" and "tolen" parameters are ignored on connection-oriented
* sockets.
*
* In case of error, bp is freed so the caller doesn't have to worry about it.
*/
int
send_mbuf(
int s, /* Socket index */
struct mbuf *bp, /* Buffer to send */
int flags, /* not currently used */
char *to, /* Destination, only for datagrams */
int tolen) /* Length of destination */
{
struct usock *up;
union cb cb;
union sp local,remote;
struct socket lsock,fsock;
int cnt;
if((up = itop(s)) == NULLUSOCK) {
free_p(bp);
return EOF;
}
if(up->obuf != NULLBUF) {
/* If there's unflushed output, send it.
* Note the importance of clearing up->obuf
* before the recursive call!
*/
struct mbuf *bp1;
bp1 = up->obuf;
up->obuf = NULLBUF;
send_mbuf(s,bp1,flags,to,tolen);
}
if(up->name == NULLCHAR) {
/* Automatic local name assignment for datagram sockets */
switch(up->type){
case TYPE_LOCAL_STREAM:
case TYPE_LOCAL_DGRAM:
break; /* no op */
#ifdef UDP
case TYPE_UDP:
#endif
case TYPE_RAW:
autobind(s,AF_INET);
break;
#ifdef AX25
case TYPE_AX25UI:
autobind(s,AF_AX25);
break;
#endif
#ifdef NETROM
case TYPE_NETROML3:
case TYPE_NETROML4:
autobind(s,AF_NETROM);
break;
#endif
default:
free_p(bp);
errno = ENOTCONN;
return EOF;
}
}
cnt = len_p(bp);
switch(up->type){
case TYPE_LOCAL_DGRAM:
if(up->cb.local->peer == NULLUSOCK){
free_p(bp);
errno = ENOTCONN;
return EOF;
}
enqueue(&up->cb.local->peer->cb.local->q,bp);
psignal(up->cb.local->peer,0);
/* If high water mark has been reached, block */
while(len_q(up->cb.local->q) >= up->cb.local->hiwat){
if(up->noblock){
errno = EWOULDBLOCK;
return EOF;
} else if((errno = (int)pwait(up->cb.local->peer)) != 0){
return EOF;
}
}
if(up->cb.local->peer == NULLUSOCK){
errno = ENOTCONN;
return EOF;
}
break;
case TYPE_LOCAL_STREAM:
if(up->cb.local->peer == NULLUSOCK){
free_p(bp);
errno = ENOTCONN;
return EOF;
}
append(&up->cb.local->peer->cb.local->q,bp);
psignal(up->cb.local->peer,0);
/* If high water mark has been reached, block */
while(up->cb.local->peer != NULLUSOCK &&
len_p(up->cb.local->peer->cb.local->q) >=
up->cb.local->peer->cb.local->hiwat){
if(up->noblock){
errno = EWOULDBLOCK;
return EOF;
} else if((errno = (int)pwait(up->cb.local->peer)) != 0){
return EOF;
}
}
if(up->cb.local->peer == NULLUSOCK){
errno = ENOTCONN;
return EOF;
}
break;
case TYPE_TCP:
if((cb.tcb = up->cb.tcb) == NULLTCB){
free_p(bp);
errno = ENOTCONN;
return EOF;
}
cnt = send_tcp(cb.tcb,bp);
while((cb.tcb = up->cb.tcb) != NULLTCB &&
cb.tcb->sndcnt > cb.tcb->window){
/* Send queue is full */
if(up->noblock){
errno = EWOULDBLOCK;
return EOF;
} else if((errno = (int)pwait(up)) != 0){
return EOF;
}
}
if(cb.tcb == NULLTCB){
errno = ENOTCONN;
return EOF;
}
break;
#ifdef UDP
case TYPE_UDP:
local.in = (struct sockaddr_in *)up->name;
lsock.address = local.in->sin_addr.s_addr;
lsock.port = local.in->sin_port;
if(to != NULLCHAR)
remote.in = (struct sockaddr_in *)to;
else if(up->peername != NULLCHAR)
remote.in = (struct sockaddr_in *)up->peername;
else {
errno = ENOTCONN;
return EOF;
}
fsock.address = remote.in->sin_addr.s_addr;
fsock.port = remote.in->sin_port;
send_udp(&lsock,&fsock,0,0,bp,0,0,0);
break;
#endif
case TYPE_RAW:
local.in = (struct sockaddr_in *)up->name;
if(to != NULLCHAR)
remote.in = (struct sockaddr_in *)to;
else if(up->peername != NULLCHAR)
remote.in = (struct sockaddr_in *)up->peername;
else {
errno = ENOTCONN;
return EOF;
}
ip_send(local.in->sin_addr.s_addr,remote.in->sin_addr.s_addr,
up->cb.rip->protocol,0,0,bp,0,0,0);
break;
#ifdef AX25
case TYPE_AX25I:
if((cb.ax25 = up->cb.ax25) == NULLAX25){
free_p(bp);
errno = ENOTCONN;
return EOF;
}
send_ax25(cb.ax25,bp,STREAM);
while((cb.ax25 = up->cb.ax25) != NULLAX25 &&
len_p(cb.ax25->txq) > Axwindow){
if(up->noblock){
errno = EWOULDBLOCK;
return EOF;
} else if((errno = (int)pwait(up)) != 0){
errno = EINTR;
return EOF;
}
}
if(cb.ax25 == NULLAX25){
errno = EBADF;
return EOF;
}
break;
case TYPE_AX25UI:
local.ax = (struct sockaddr_ax *)up->name;
if(to != NULLCHAR)
remote.ax = (struct sockaddr_ax *)to;
else if(up->peername != NULLCHAR)
remote.ax = (struct sockaddr_ax *)up->peername;
else {
errno = ENOTCONN;
return EOF;
}
ax_output(if_lookup(remote.ax->iface),
remote.ax->ax25_addr,
local.ax->ax25_addr,PID_NO_L3,bp);
break;
#endif
#ifdef NETROM
case TYPE_NETROML3:
if(len_p(bp) > Nr_iface->mtu) {
free_p(bp);
errno = EMSGSIZE;
return EOF;
}
local.nr = (struct sockaddr_nr *)up->name;
if(to != NULLCHAR)
remote.nr = (struct sockaddr_nr *)to;
else if(up->peername != NULLCHAR)
remote.nr = (struct sockaddr_nr *)up->peername;
else {
errno = ENOTCONN;
return EOF;
}
/* The NETROM username is always ignored in outgoing traffic */
nr_sendraw(remote.nr->nr_addr.node,
up->cb.rnr->protocol,up->cb.rnr->protocol,bp);
break;
case TYPE_NETROML4:
if((cb.nr4 = up->cb.nr4) == NULLNR4CB) {
free_p(bp);
errno = ENOTCONN;
return EOF;
}
if(len_p(bp) > Nr_iface->mtu){ /* reject big packets */
free_p(bp);
errno = EMSGSIZE;
return EOF;
}
send_nr4(cb.nr4,bp);
while((cb.nr4 = up->cb.nr4) != NULLNR4CB &&
cb.nr4->nbuffered >= cb.nr4->window){
if(up->noblock){
errno = EWOULDBLOCK;
return EOF;
} else if((errno = (int)pwait(up)) != 0){
errno = EINTR;
return EOF;
}
}
if(cb.nr4 == NULLNR4CB){
errno = EBADF;
return EOF;
}
break;
#endif
}
return cnt;
}
/* Return local name passed in an earlier bind() call */
int
getsockname(
int s, /* Socket index */
char *name, /* Place to stash name */
int *namelen) /* Length of same */
{
struct usock *up;
if((up = itop(s)) == NULLUSOCK){
return EOF;
}
if(name == NULLCHAR || namelen == 0){
errno = EFAULT;
return EOF;
}
if(up->name == NULLCHAR){
/* Not bound yet */
*namelen = 0;
return 0;
}
if(up->name != NULLCHAR){
*namelen = (int)min(*namelen,up->namelen);
memcpy(name,up->name,*namelen);
}
return 0;
}
/* Get remote name, returning result of earlier connect() call. */
int
getpeername(
int s, /* Socket index */
char *peername, /* Place to stash name */
int *peernamelen) /* Length of same */
{
struct usock *up;
if((up = itop(s)) == NULLUSOCK){
return EOF;
}
if(up->peername == NULLCHAR){
errno = ENOTCONN;
return EOF;
}
if(peername == NULLCHAR || peernamelen == 0){
errno = EFAULT;
return EOF;
}
*peernamelen = (int)min(*peernamelen,up->peernamelen);
memcpy(peername,up->peername,*peernamelen);
return 0;
}
/* Return length of protocol queue, either send or receive. */
int
socklen(
int s, /* Socket index */
int rtx) /* 0 = receive queue, 1 = transmit queue */
{
struct usock *up;
int len = -1;
if((up = itop(s)) == NULLUSOCK){
return EOF;
}
if(up->cb.p == NULLCHAR){
errno = ENOTCONN;
return EOF;
}
if(rtx < 0 || rtx > 1) {
errno = EINVAL;
return EOF;
}
switch(up->type){
case TYPE_LOCAL_DGRAM:
switch(rtx){
case 0:
len = len_q(up->cb.local->q);
break;
case 1:
if(up->cb.local->peer != NULLUSOCK) {
len = len_q(up->cb.local->peer->cb.local->q);
}
break;
}
break;
case TYPE_LOCAL_STREAM:
switch(rtx){
case 0:
len = len_p(up->cb.local->q) + len_p(up->ibuf);
break;
case 1:
if(up->cb.local->peer != NULLUSOCK) {
len = len_p(up->cb.local->peer->cb.local->q) + len_p(up->obuf);
}
break;
}
break;
case TYPE_TCP:
switch(rtx){
case 0:
len = up->cb.tcb->rcvcnt + len_p(up->ibuf);
break;
case 1:
len = up->cb.tcb->sndcnt + len_p(up->obuf);
break;
}
break;
#ifdef UDP
case TYPE_UDP:
switch(rtx){
case 0:
len = up->cb.udp->rcvcnt;
break;
case 1:
len = 0;
break;
}
break;
#endif
#ifdef AX25
case TYPE_AX25I:
switch(rtx){
case 0:
len = len_p(up->cb.ax25->rxq) + len_p(up->ibuf);
break;
case 1: /* Number of bytes, not packets. DB3FL.910129 */
len = len_p(up->cb.ax25->txq);
if(up->obuf != NULLBUF)
len++;
}
break;
case TYPE_AX25UI:
switch(rtx){
case 0:
case 1:
len = 0;
break;
}
break;
#endif
#ifdef NETROM
case TYPE_NETROML3:
switch(rtx){
case 0:
len = len_q(up->cb.rnr->rcvq);
break;
case 1:
len = 0;
break;
}
break;
case TYPE_NETROML4:
switch(rtx){
case 0:
len = len_p(up->cb.nr4->rxq) + len_p(up->obuf);
break;
case 1: /* Number of bytes, not packets. DB3FL.900129 */
len = len_p(up->cb.nr4->txq);
if(up->obuf != NULLBUF)
len++;
break;
}
break;
#endif
case TYPE_RAW:
switch(rtx){
case 0:
len = len_q(up->cb.rip->rcvq);
break;
case 1:
len = 0;
break;
}
break;
}
return len;
}
/* Force retransmission. Valid only for connection-oriented sockets. */
int
sockkick(int s)
{
struct usock *up;
if((up = itop(s)) == NULLUSOCK){
return EOF;
}
if(up->type == TYPE_LOCAL_STREAM || up->type == TYPE_LOCAL_DGRAM){
errno = EINVAL;
return EOF;
}
if(up->cb.p == NULLCHAR){
errno = ENOTCONN;
return EOF;
}
switch(up->type){
case TYPE_TCP:
kick_tcp(up->cb.tcb);
break;
#ifdef AX25
case TYPE_AX25I:
kick_ax25(up->cb.ax25);
break;
#endif
#ifdef NETROM
case TYPE_NETROML4:
kick_nr4(up->cb.nr4);
break;
#endif
default:
/* Datagram sockets can't be kicked */
errno = EOPNOTSUPP;
return EOF;
}
return 0;
}
/* Change owner of socket, return previous owner */
struct proc *
sockowner(int s,struct proc *newowner)
{
struct usock *up;
struct proc *pp;
if((up = itop(s)) == NULLUSOCK){
return NULLPROC;
}
pp = up->owner;
if(newowner != NULLPROC)
up->owner = newowner;
return pp;
}
/* Close down a socket three ways. Type 0 means "no more receives"; this
* replaces the incoming data upcall with a routine that discards further
* data. Type 1 means "no more sends", and obviously corresponds to sending
* a TCP FIN. Type 2 means "no more receives or sends". This I interpret
* as "abort the connection".
*/
int
shutdown(int s,int how)
{
struct usock *up;
if((up = itop(s)) == NULLUSOCK){
return EOF;
}
if(up->cb.p == NULLCHAR){
errno = ENOTCONN;
return EOF;
}
switch(up->type){
case TYPE_LOCAL_DGRAM:
case TYPE_LOCAL_STREAM:
if(up->cb.local->q == NULLBUF)
close_s(s);
else
up->cb.local->flags = LOC_SHUTDOWN;
break;
case TYPE_TCP:
switch(how){
case 0: /* No more receives -- replace upcall */
up->cb.tcb->r_upcall = trdiscard;
break;
case 1: /* Send EOF */
close_tcp(up->cb.tcb);
break;
case 2: /* Blow away TCB */
reset_tcp(up->cb.tcb);
up->cb.tcb = NULLTCB;
break;
}
break;
#ifdef AX25
case TYPE_AX25UI:
close_s(s);
break;
case TYPE_AX25I:
switch(how){
case 0:
case 1: /* Attempt regular disconnect */
disc_ax25(up->cb.ax25);
break;
case 2: /* Blow it away */
reset_ax25(up->cb.ax25);
up->cb.ax25 = NULLAX25;
break;
}
break;
#endif
#ifdef NETROM
case TYPE_NETROML3:
close_s(s);
break;
case TYPE_NETROML4:
switch(how){
case 0:
case 1: /* Attempt regular disconnect */
disc_nr4(up->cb.nr4);
break;
case 2: /* Blow it away */
reset_nr4(up->cb.nr4);
up->cb.nr4 = NULLNR4CB;
break;
}
break;
#endif
case TYPE_RAW:
#ifdef UDP
case TYPE_UDP:
#endif
close_s(s);
break;
default:
errno = EOPNOTSUPP;
return EOF;
}
psignal(up,0);
return 0;
}
/* Close a socket, freeing it for reuse. Try to do a graceful close on a
* TCP socket, if possible
*/
int
close_s(int s)
{
struct usock *up;
if((up = itop(s)) == NULLUSOCK){
return EOF;
}
if(--up->refcnt > 0) {
/* Others are still using it */
return 0;
}
usflush(s);
if(up->ibuf != NULLBUF) {
free_p(up->ibuf);
up->ibuf = NULLBUF;
}
switch(up->type) {
case TYPE_LOCAL_STREAM:
case TYPE_LOCAL_DGRAM:
if(up->cb.local->peer != NULLUSOCK) {
up->cb.local->peer->cb.local->peer = NULLUSOCK;
psignal(up->cb.local->peer,0);
}
free_q(&up->cb.local->q);
xfree(up->cb.local);
break;
case TYPE_TCP:
if(up->cb.tcb != NULLTCB) { /* In case it's been reset */
up->cb.tcb->r_upcall = trdiscard;
/* Tell the TCP_CLOSED upcall there's no more socket */
up->cb.tcb->user = -1;
close_tcp(up->cb.tcb);
}
break;
#ifdef UDP
case TYPE_UDP:
if(up->cb.udp != NULLUDP) {
del_udp(up->cb.udp);
}
break;
#endif
#ifdef AX25
case TYPE_AX25I:
if(up->cb.ax25 != NULLAX25) {
/* Tell the TCP_CLOSED upcall there's no more socket */
up->cb.ax25->user = -1;
disc_ax25(up->cb.ax25);
}
break;
case TYPE_AX25UI:
Axui_sock = -1;
break;
#endif
#ifdef NETROM
case TYPE_NETROML3:
del_rnr(up->cb.rnr);
break;
case TYPE_NETROML4:
if(up->cb.nr4 != NULLNR4CB) {
/* Tell the TCP_CLOSED upcall there's no more socket */
up->cb.nr4->user = -1;
disc_nr4(up->cb.nr4);
}
break;
#endif
case TYPE_RAW:
del_ip(up->cb.rip);
break;
default:
errno = EOPNOTSUPP;
return EOF;
}
#ifdef LZW
if(up->zout != NULLLZW || up->zin != NULLLZW)
lzwfree(up);
#endif
if(up->name != NULLCHAR) {
xfree(up->name);
}
if(up->peername != NULLCHAR) {
xfree(up->peername);
}
up->name = up->peername = NULLCHAR;
up->namelen = up->peernamelen = 0;
up->cb.p = NULLCHAR;
up->type = NOTUSED;
/* Wake up anybody doing an accept() or recv() */
psignal(up,0);
return 0;
}
/* Increment reference count for specified socket */
int
usesock(int s)
{
struct usock *up;
if((up = itop(s)) == NULLUSOCK){
return EOF;
}
up->refcnt++;
return 0;
}
/* Blow away all sockets belonging to a certain process. Used by killproc(). */
void
freesock(struct proc *pp)
{
struct usock *up;
int i;
for(i = SOCKBASE; i < (Nusock + SOCKBASE); i++)
if((up = itop(i)) != NULLUSOCK)
if(up->type != NOTUSED && up->owner == pp)
shutdown(i,2);
}
/* Start of internal subroutines */
/* Raw IP receive upcall routine */
static void
rip_recv(struct raw_ip *rp)
{
psignal(itop(rp->user),1);
pwait(NULL);
}
#ifdef UDP
/* UDP receive upcall routine */
static void
s_urcall(struct iface *iface,struct udp_cb *udp,int cnt)
{
psignal(itop(udp->user),1);
pwait(NULL);
}
#endif
/* TCP receive upcall routine */
static void
s_trcall(struct tcb *tcb,int cnt)
{
/* Wake up anybody waiting for data, and let them run */
psignal(itop(tcb->user),1);
pwait(NULL);
}
/* TCP transmit upcall routine */
static void
s_ttcall(struct tcb *tcb,int cnt)
{
/* Wake up anybody waiting to send data, and let them run */
psignal(itop(tcb->user),1);
pwait(NULL);
}
/* TCP state change upcall routine */
static void
s_tscall(struct tcb *tcb,int old,int new)
{
int s = tcb->user, ns;
union sp sp;
struct usock *nup, *oup, *up = itop(s);
oup = up;
switch(new){
case TCP_CLOSED:
/* Clean up. If the user has already closed the socket,
* then up will be null (s was set to -1 by the close routine).
* If not, then this is an abnormal close (e.g., a reset)
* and clearing out the pointer in the socket structure will
* prevent any further operations on what will be a freed
* control block. Also wake up anybody waiting on events
* related to this tcb so they will notice it disappearing.
*/
if(up != NULLUSOCK){
up->cb.tcb = NULLTCB;
up->errcodes[0] = tcb->reason;
up->errcodes[1] = tcb->type;
up->errcodes[2] = tcb->code;
}
del_tcp(tcb);
break;
case TCP_SYN_RECEIVED:
/* Handle an incoming connection. If this is a server TCB,
* then we're being handed a "clone" TCB and we need to
* create a new socket structure for it. In either case,
* find out who we're talking to and wake up the guy waiting
* for the connection.
*/
if(tcb->flags.clone){
/* Clone the socket */
ns = socket(AF_INET,SOCK_STREAM,0);
nup = itop(ns);
ASSIGN(*nup,*up);
tcb->user = ns;
nup->cb.tcb = tcb;
/* Allocate new memory for the name areas */
nup->name = mxallocw(SOCKSIZE);
nup->peername = mxallocw(SOCKSIZE);
/* Store the new socket # in the old one */
up->rdysock = ns;
up = nup;
s = ns;
} else {
/* Allocate space for the peer's name */
up->peername = mxallocw(SOCKSIZE);
/* Store the old socket # in the old socket */
up->rdysock = s;
}
/* Load the addresses. Memory for the name has already
* been allocated, either above or in the original bind.
*/
sp.p = up->name;
sp.in->sin_family = AF_INET;
sp.in->sin_addr.s_addr = up->cb.tcb->conn.local.address;
sp.in->sin_port = up->cb.tcb->conn.local.port;
up->namelen = SOCKSIZE;
sp.p = up->peername;
sp.in->sin_family = AF_INET;
sp.in->sin_addr.s_addr = up->cb.tcb->conn.remote.address;
sp.in->sin_port = up->cb.tcb->conn.remote.port;
up->peernamelen = SOCKSIZE;
/* Wake up the guy accepting it, and let him run */
psignal(oup,1);
pwait(NULL);
break;
default: /* Ignore all other state transitions */
break;
}
psignal(up,0); /* In case anybody's waiting */
}
/* Discard data received on a TCP connection. Used after a receive shutdown or
* close_s until the TCB disappears.
*/
static void
trdiscard(struct tcb *tcb,int cnt)
{
struct mbuf *bp;
recv_tcp(tcb,&bp,cnt);
free_p(bp);
}
/*
#ifdef AX25 DB3FL
*/
/* AX.25 receive upcall */
void
s_arcall(struct ax25_cb *axp,int cnt)
{
int ns;
union sp sp;
struct usock *nup, *oup, *up = itop(axp->user);
/* When AX.25 data arrives for the first time the AX.25 listener
is notified, if active. If the AX.25 listener is a server its
socket is duplicated in the same manner as in s_tscall().
*/
if (Axi_sock != -1 && axp->user == -1) {
oup = up = itop(Axi_sock);
/* From now on, use the same upcalls as the listener */
axp->t_upcall = up->cb.ax25->t_upcall;
axp->r_upcall = up->cb.ax25->r_upcall;
axp->s_upcall = up->cb.ax25->s_upcall;
if (up->cb.ax25->clone) {
/* Clone the socket */
ns = socket(AF_AX25,SOCK_STREAM,0);
nup = itop(ns);
ASSIGN(*nup,*up);
axp->user = ns;
nup->cb.ax25 = axp;
/* Allocate new memory for the name areas */
nup->name = mxallocw(sizeof(struct sockaddr_ax));
nup->peername = mxallocw(sizeof(struct sockaddr_ax));
/* Store the new socket # in the old one */
up->rdysock = ns;
up = nup;
} else {
axp->user = Axi_sock;
del_ax25(up->cb.ax25);
up->cb.ax25 = axp;
/* Allocate space for the peer's name */
up->peername = mxallocw(sizeof(struct sockaddr_ax));
/* Store the old socket # in the old socket */
up->rdysock = Axi_sock;
}
/* Load the addresses. Memory for the name has already
* been allocated, either above or in the original bind.
*/
sp.p = up->name;
sp.ax->sax_family = AF_AX25;
memcpy(sp.ax->ax25_addr,axp->path + AXALEN,AXALEN);
memcpy(sp.ax->iface,axp->iface->name,ILEN);
up->namelen = sizeof(struct sockaddr_ax);
sp.p = up->peername;
sp.ax->sax_family = AF_AX25;
memcpy(sp.ax->ax25_addr,axp->path,AXALEN);
memcpy(sp.ax->iface,axp->iface->name,ILEN);
up->peernamelen = sizeof(struct sockaddr_ax);
/* Wake up the guy accepting it, and let him run */
psignal(oup,1);
pwait(NULL);
return;
}
/* Wake up anyone waiting, and let them run */
psignal(up,1);
pwait(NULL);
}
/* AX.25 transmit upcall */
void
s_atcall(struct ax25_cb *axp,int cnt)
{
/* Wake up anyone waiting, and let them run */
psignal(itop(axp->user),1);
pwait(NULL);
}
/* AX25 state change upcall routine */
void
s_ascall(struct ax25_cb *axp,int old,int new)
{
struct usock *up = itop(axp->user);
switch(new){
case DISCONNECTED:
/* Clean up. If the user has already closed the socket,
* then up will be null (s was set to -1 by the close routine).
* If not, then this is an abnormal close (e.g., a reset)
* and clearing out the pointer in the socket structure will
* prevent any further operations on what will be a freed
* control block. Also wake up anybody waiting on events
* related to this block so they will notice it disappearing.
*/
if(up != NULLUSOCK){
up->errcodes[0] = axp->reason;
up->cb.ax25 = NULLAX25;
}
del_ax25(axp);
default: /* Other transitions are ignored */
break;
}
psignal(up,0); /* In case anybody's waiting */
}
/*
#endif
*/
#ifdef NETROM
/* NET/ROM receive upcall routine */
void
s_nrcall(struct nr4cb *cb,int cnt)
{
/* Wake up anybody waiting for data, and let them run */
psignal(itop(cb->user),1);
pwait(NULL);
}
/* NET/ROM transmit upcall routine */
void
s_ntcall(struct nr4cb *cb,int cnt)
{
/* Wake up anybody waiting to send data, and let them run */
psignal(itop(cb->user),1);
pwait(NULL);
}
/* NET/ROM state change upcall routine */
void
s_nscall(struct nr4cb *cb,int old,int new)
{
int ns, s = cb->user;
struct usock *oup, *nup, *up = itop(s);
union sp sp;
oup = up;
if(new == NR4STDISC && up != NULLUSOCK){
/* Clean up. If the user has already closed the socket,
* then up will be null (s was set to -1 by the close routine).
* If not, then this is an abnormal close (e.g., a reset)
* and clearing out the pointer in the socket structure will
* prevent any further operations on what will be a freed
* control block. Also wake up anybody waiting on events
* related to this cb so they will notice it disappearing.
*/
up->cb.nr4 = NULLNR4CB;
up->errcodes[0] = cb->dreason;
}
if(new == NR4STCON && old == NR4STDISC){
/* Handle an incoming connection. If this is a server cb,
* then we're being handed a "clone" cb and we need to
* create a new socket structure for it. In either case,
* find out who we're talking to and wake up the guy waiting
* for the connection.
*/
if(cb->clone){
/* Clone the socket */
ns = socket(AF_NETROM,SOCK_SEQPACKET,0);
nup = itop(ns);
ASSIGN(*nup,*up);
cb->user = ns;
nup->cb.nr4 = cb;
cb->clone = 0; /* to avoid getting here again */
/* Allocate new memory for the name areas */
nup->name = mxallocw(sizeof(struct sockaddr_nr));
nup->peername = mxallocw(sizeof(struct sockaddr_nr));
/* Store the new socket # in the old one */
up->rdysock = ns;
up = nup;
s = ns;
} else {
/* Allocate space for the peer's name */
up->peername = mxallocw(sizeof(struct sockaddr_nr));
/* Store the old socket # in the old socket */
up->rdysock = s;
}
/* Load the addresses. Memory for the name has already
* been allocated, either above or in the original bind.
*/
sp.p = up->name;
sp.nr->nr_family = AF_NETROM;
ASSIGN(sp.nr->nr_addr,up->cb.nr4->local);
up->namelen = sizeof(struct sockaddr_nr);
sp.p = up->peername;
sp.nr->nr_family = AF_NETROM;
ASSIGN(sp.nr->nr_addr,up->cb.nr4->remote);
up->peernamelen = sizeof(struct sockaddr_nr);
/* Wake up the guy accepting it, and let him run */
psignal(oup,1);
pwait(NULL);
}
/* Ignore all other state transitions */
psignal(up,0); /* In case anybody's waiting */
}
#endif
/* Verify address family and length according to the socket type */
static int near
checkaddr(int type,char *name,int namelen)
{
struct sockaddr *sp = (struct sockaddr *)name;
/* Verify length and address family according to protocol */
switch(type){
case TYPE_TCP:
#ifdef UDP
case TYPE_UDP:
#endif
if(sp->sa_family != AF_INET
|| namelen != sizeof(struct sockaddr_in))
return EOF;
break;
#ifdef AX25
case TYPE_AX25I:
case TYPE_AX25UI:
if(sp->sa_family != AF_AX25
|| namelen != sizeof(struct sockaddr_ax))
return EOF;
break;
#endif
#ifdef NETROM
case TYPE_NETROML3:
case TYPE_NETROML4:
if(sp->sa_family != AF_NETROM
|| namelen != sizeof(struct sockaddr_nr))
return EOF;
break;
#endif
}
return 0;
}
/* Issue an automatic bind of a local address */
static void near
autobind(int s,int af)
{
char buf[MAXSOCKSIZE];
union sp sp;
memset(buf,0,sizeof(buf));
sp.p = buf;
switch(af){
case AF_INET:
sp.in->sin_family = AF_INET;
sp.in->sin_addr.s_addr = INADDR_ANY;
sp.in->sin_port = Lport++;
bind(s,sp.p,sizeof(struct sockaddr_in));
break;
#ifdef AX25
case AF_AX25:
sp.ax->sax_family = AF_AX25;
memset(sp.ax->ax25_addr,'\0',AXALEN);
memset(sp.ax->iface,'\0',ILEN);
bind(s,sp.p,sizeof(struct sockaddr_ax));
break;
#endif
#ifdef NETROM
case AF_NETROM:
sp.nr->nr_family = AF_NETROM;
memcpy(sp.nr->nr_addr.user,Mycall,AXALEN);
memcpy(sp.nr->nr_addr.node,Mycall,AXALEN);
bind(s,sp.p,sizeof(struct sockaddr_nr));
break;
#endif
}
}
/* Convert a socket index to an internal user socket structure pointer */
struct usock *
itop(int s) /* Socket index */
{
int sidx = s - SOCKBASE;
struct usock *up = &Usock[sidx];
if(up->type == NOTUSED || sidx < 0 || sidx >= Nusock) {
errno = EBADF;
return NULLUSOCK;
}
return up;
}